home *** CD-ROM | disk | FTP | other *** search
- /*
- File: SysProc.cpp
-
- Contains: OpenDoc™ System Process
-
- Owned by: Nick Pilch
-
- Copyright: © 1993 - 1997 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <21> 1/8/97 DH 1401434: Specifically check if document is
- missing and report to the user in
- HandleCloseReopenEvent;
- Also don't return error back to AE Mgr,
- since it has been reported already;
- increase time to wait for document to close
- before reopening it.
- <20> 10/23/96 DH Fixed another build break problem.
- <19> 10/23/96 TJ Made it compile.
- <18> 10/23/96 DH 1336808 ,1333949,1368888,1375780 If doc
- doesn't launch because of out-of-memory,
- send event to OpenDoc to adjust memory
- size.
- <17> 10/5/96 NP Fixed notification manager interactions.
- <16> 10/5/96 NP Debug build only messsages to heap with
- debugging.
- <15> 02.10.1996 NP 1391011: hard-coded strings
- <14> 27.09.1996 NP 1332145: Bad message when launch fails
- <13> 11.09.1996 NP 1386084: undo changes that tried to
- accomodate old launcher
- <12> 7/11/96 TJ Fixed Name of function to check for MacOS 8
- <11> 11.07.1996 NP 1365143: Can't find system process error
- messages.
- <10> 6/26/96 NP 10002: Launch time speedups.
- <9> 6/23/96 NP 1361269: Wait until notification manager
- tasks have completed before quitting.
- 1323565: Refuse to run under MacOS 8.
- <8> 6/19/96 NP 10002: Launch time speedups.
- <7> 6/18/96 NP 10002: Launch time speedups.
- <6> 6/14/96 NP 10002: Launch time speedups
- <5> .05.1996 NP 10002: Launch time fixes.
- <4> .05.1996 NP More implementation.
- <3> .05.1996 NP Working on it.
- <2> .04.1996 NP Check in comment about bug that might have
- to be worked around.
- <1> .04.1996 NP first checked in
-
- To Do:
-
- In Progress:
-
- */
-
-
- #ifndef __LIMITS__
- #include <Limits.h>
- #endif
-
- #ifndef __GESTALT__
- #include <Gestalt.h>
- #endif
-
- #ifndef __TEXTUTILS__
- #include <TextUtils.h>
- #endif
-
- #ifndef __SCRAP__
- #include <Scrap.h>
- #endif
-
- #ifndef __TOOLUTILS__
- #include <ToolUtils.h>
- #endif
-
- #ifndef __ALIASES__
- #include <Aliases.h>
- #endif
-
-
- #ifndef _PASCLSTR_
- #include "PasclStr.h"
- #endif
-
- #ifndef _ODXFUNCS_
- #include "ODXFuncs.h"
- #endif
-
- #ifndef _ODXDPFNS_
- #include "ODXDpFns.h"
- #endif
-
- #ifndef _ODPRCS_
- #include "ODPrcs.h"
- #endif
-
- #ifndef _ODDEBUG_
- #include "ODDebug.h"
- #endif
-
- #ifndef _EXCEPT_
- #include "Except.h"
- #endif
-
- #ifndef _ODMEMORY_
- #include "ODMemory.h"
- #endif
-
- #ifndef _SHELLDEF_
- #include "ShellDef.h"
- #endif
-
- #ifndef _PLFMFILE_
- #include "PlfmFile.h"
- #endif
-
- #ifndef _TEMPOBJ_
- #include "TempObj.h"
- #endif
-
- #ifndef _INFOUTIL_
- #include "InfoUtil.h"
- #endif
-
- #ifndef _SEUTILS_
- #include "SEUtils.h"
- #endif
-
- #ifndef _MEMDEBG_
- #include "MemDebg.h"
- #endif
-
- #ifndef ODDebug
- #error "Expected \"ODDebug\" to be defined."
- #endif
-
- //==============================================================================
- // Constants
- //==============================================================================
-
- // This is ten seconds in ticks.
- #define kWaitNumTicks 10*60
- const unsigned long kWaitForDocClosedTicks = 60*100; // Time to wait for document
- // to close when trying to reopen it.
-
- //==============================================================================
- // Globals
- //==============================================================================
-
- #ifndef __MWERKS__
- QDGlobals qd;
- #endif
-
- //==============================================================================
- // Macros
- //==============================================================================
-
- //#define CHECK(EXPR) if((err=(EXPR)) == noErr) ; else return err
-
- //==============================================================================
- // Function Prototypes
- //==============================================================================
-
- static void MainEventLoop();
- static pascal OSErr HandleQuit(const AppleEvent*, AppleEvent*, long);
- static long GetSleepTime();
- static void InstallEventHandler(AEEventClass theAEEventClass,
- AEEventID theAEEventID,
- AEEventHandlerProcPtr handler);
- static AEEventHandlerUPP CreateAEEventHandlerUPP(
- AEEventHandlerProcPtr handler);
- static void ReportErrorWithNum(StringPtr errorString,
- OSErr error);
- static void ReportError(StringPtr errorString);
- static pascal void InstallNotification(StringPtr errorString);
- static ODBoolean ShouldIQuit();
- static OSType GetOurCreator();
- static void ChangeOurCreator(OSType);
- static OSErr FindLauncher(FSSpec* fileSpec);
- static OSErr ReenableLauncher();
- static OSErr EnableApp(FSSpec* fileSpec);
- static OSErr EnableAppIfNotAlready(FSSpec* fileSpec);
- static void DisableApp(FSSpec* fileSpec, OSType newSignature);
- static OSErr DoCatSearchesAndEnable(OSType creator);
- static void DeleteOldLauncher();
- static pascal OSErr HandleControlMessage(const AppleEvent*, AppleEvent*, long);
- static pascal OSErr HandleCloseReopenEvent(const AppleEvent*, AppleEvent*, long);
- void CheckPrefs();
- static void CheckForCorrectName();
- static ODBoolean SystemIsTooOld();
- #if !GENERATINGCFM
- ODBoolean CFMIsPresent();
- #endif
-
-
- //==============================================================================
- // Code
- //==============================================================================
-
- //------------------------------------------------------------------------------
- // CFM Init routine, SysProcCFMInit
- //------------------------------------------------------------------------------
-
- FSSpec gFileSpec;
-
- extern "C" pascal OSErr SysProcCFMInit(CFragInitBlockPtr initBlkPtr);
- pascal OSErr SysProcCFMInit(CFragInitBlockPtr initBlkPtr)
- {
- OSErr result = noErr;
-
- switch( initBlkPtr->fragLocator.where )
- {
- case kDataForkCFragLocator:
- case kResourceCFragLocator:
- gFileSpec = *(initBlkPtr->fragLocator.u.onDisk.fileSpec);
- break;
- default:
- result = fragCorruptErr;
- WARN("SysProcCFMInit: Not expecting this code fragment"
- " location %ld!", initBlkPtr->fragLocator.where);
- break;
- }
-
- return result;
- }
-
- //------------------------------------------------------------------------------
- // main
- //------------------------------------------------------------------------------
-
- // IF WE ARE LAUNCHED WITH CREATOR kODShellSignature, WE MUST NOT RUN. OTHERWISE
- // WE ARE TRYING TO ACT AS THE LAUNCHER, BUT CAN NEVER GET OPEN DOCUMENT EVENTS
- ODBoolean gShouldRun = kODTrue;
-
- // MAKE SURE WE DON'T GO AWAY BEFORE ALL NOTIFICATION MANAGER TASKS ARE REMOVED
- long gPendingNotifications = 0;
-
- ODBoolean gIsSystem753OrLater;
-
- ODBoolean gRunUntilQuitEvent = false;
-
- Size gSize = kDocStubDefaultSize;
-
- void main(void)
- {
- OSErr error;
- /*
- Here's something I found in a technote (PS02):
-
- Currently there is a bug with 'appe's that have an 'INIT' under System 7.5 with
- PowerTalk installed. The BOA's heap can be corrupted if MaxApplZone is called.
- The current workaround is to compare the low-memory global HeapEnd to the BOA's
- bkLim field of its zone (obtained by calling GetZone). If the two values aren't
- the same, set HeapEnd to the value contained in theZone->bkLim (use the low
- memory accessors LMGetHeapEnd and LMSetHeapEnd to access/modify the low memory
- global.) This should be the first thing done in your BOA code, before setting
- the stack size or calling MaxApplZone.
- */
- MaxApplZone();
- // MoreMasters();
-
- // The scrap is copied into our application heap when the process is launched,
- // occuping space otherwise used for launching documents.
- // If the scrap is just the right size (approx. 30K), there isn't enough
- // heap space left to launch a single document (the launcher will bail with
- // error -108). Worse, if the scrap is just the right size, around 40K,
- // InitWindows will hang the system. To avoid this, always unload the scrap.
- // Testing for a nil scrap handle seems to avoid a write to nil by UnloadScrap.
- // [cc]
- if ( InfoScrap()->scrapHandle != nil )
- UnloadScrap();
-
- InitGraf((Ptr)&qd.thePort);
-
- #if !GENERATINGCFM
- if ( ! CFMIsPresent())
- return;
- #endif
-
- // WARNING. MUST CALL InitODMemory AND ODInitExceptions BEFORE USING ANY
- // EXCEPTION AND MEMORY UTILITIES!!!!!
- error = InitODMemory();
- if (error)
- {
- Str255 errorString;
-
- GetIndString(errorString, kODSysProcStringsID,
- kODSPStrIndexNoMemoryToStartUp);
- ReportErrorWithNum(errorString, error);
- goto bail;
- }
- ODInitExceptions(); // Sets up SOMError and SOMPrintf
-
- if (SystemIsTooOld())
- goto bail;
-
- // see how long we should stick around.
- CheckPrefs();
-
- #if ODDebug
- if (IsOptionKeyDown())
- WARN("Beginning of System Process main.");
- #endif
- #if 0 /* don't do this stuff anymore, but should check system version */
- // CHECK TO SEE IF IT'S APPROPRIATE FOR US TO BE LAUNCHED.
- // DISABLE LAUNCHER FUNCTIONALITY IF WE ARE RUNNING ON OLD SYSTEMS.
- OSType creator = GetOurCreator();
- gIsSystem753OrLater = IsSystem753OrGreater();
- if (!gIsSystem753OrLater)
- {
- if (creator != kODSystemProcessSignature)
- {
- // ONLY IF WE CAN MAKE SURE A LAUNCHER IS ENABLED SHOULD WE DISABLE
- // OURSELVES
- if (!ReenableLauncher())
- {
- DisableApp(&gFileSpec, kODSystemProcessSignature);
- gShouldRun = kODFalse;
- }
- }
- }
- else
- {
- // ALWAYS CHECK TO SEE IF MY NAME IS CORRECT. IF NOT, RENAME THE
- // LAUNCHER, AND THEN RENAME OURSELVES.
- CheckForCorrectName();
- // THIS IS THE CASE I CARE MORE ABOUT. USER CAN ONLY UPGRADE A
- // PARTICULAR SYSTEM, NOT DOWNGRADE IT.
- if (creator != kODShellSignature)
- EnableApp(&gFileSpec);
- }
- #endif /* 0 */
- TRY
- AEEventHandlerUPP handlerUPP;
-
- InstallEventHandler(kCoreEventClass, kAEQuitApplication, HandleQuit);
-
- handlerUPP = CreateAEEventHandlerUPP(HandleRequiredEvent);
- THROW_IF_ERROR(AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
- handlerUPP, 0, false));
- THROW_IF_ERROR(AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
- handlerUPP, 0, false));
-
- handlerUPP = NewAEEventHandlerProc(HandleLaunchFailed);
- THROW_IF_ERROR(AEInstallEventHandler(kCoreEventClass,
- kAEApplicationDied, handlerUPP, 0, false));
- THROW_IF_ERROR(AEInstallEventHandler(kCFMLaunchFailedEventClass,
- kCFMLaunchFailedEventID, handlerUPP, 0, false));
-
- InstallEventHandler(kODShellSignature, kSysProcControlEventID,
- HandleControlMessage);
- InstallEventHandler(kODShellSignature, kODReopenDocEventID,
- HandleCloseReopenEvent);
- CATCH_ALL
- WARN("COULDN'T EVEN INITIALIZE THE SYSTEM PROCESS!");
- Str255 errorString;
-
- GetIndString(errorString, kODSysProcStringsID,
- kODSPStrIndexUnrecoverableStartUpError);
- ReportErrorWithNum(errorString, error);
- goto bail;
- ENDTRY
-
- // ODSession* session;
-
- // TRY
- // session = new ODSession;
- // THROW_IF_NULL(session);
- // session->InitSession(somGetGlobalEnvironment());
- // CATCH_ALL
- // ReportErrorWithNum("Initialization of OpenDoc failed, dude.", ErrorCode());
- // return;
- // ENDTRY
-
- MainEventLoop();
-
- bail:
-
- EventRecord anEvent;
- while(gPendingNotifications)
- WaitNextEvent(everyEvent, &anEvent, 0, (RgnHandle) nil);
- // delete session;
- }
-
- //------------------------------------------------------------------------------
- // CreateAEEventHandlerUPP
- //------------------------------------------------------------------------------
-
- static AEEventHandlerUPP CreateAEEventHandlerUPP(AEEventHandlerProcPtr handler)
- {
- AEEventHandlerUPP handlerUPP = NewAEEventHandlerProc(handler);
- THROW_IF_NULL(handlerUPP);
- return handlerUPP;
- }
-
- //------------------------------------------------------------------------------
- // InstallEventHandler
- //------------------------------------------------------------------------------
-
- static void InstallEventHandler(AEEventClass theAEEventClass,
- AEEventID theAEEventID,
- AEEventHandlerProcPtr handler)
- {
- AEEventHandlerUPP handlerUPP = CreateAEEventHandlerUPP(handler);
- THROW_IF_ERROR(AEInstallEventHandler(theAEEventClass, theAEEventID,
- handlerUPP, 0, false)); // no refcon, not a system handler
- }
-
- //------------------------------------------------------------------------------
- // MainEventLoop
- //------------------------------------------------------------------------------
-
- static Boolean gShouldQuit = false;
-
-
- const ODULong kSleepTime = 10 * 60; // time (in ticks) to wait before returning
- // from WaitNextEvent
- // OLD LAUNCHER BEHAVIOR
- const ODULong kWaitForErrorDelay = 8 * 60; // time (in ticks) to wait for
- // "couldn't launch" Apple
- // event when we are acting
- // like the old launcher.
- const ODULong kOLQuitDelay = 1 * 60; // time (in ticks) to wait for open
- // document event.
- static ODULong gQuitTime;
-
- // NEW LAUNCHER BEHAVIOR
- const ODULong kNLQuitDelay = 5 * 60; // time (in ticks) to wait until quitting
- // when no OD documents are running.
-
- static void MainEventLoop(void)
- {
- EventRecord anEvent;
- OSErr error;
- Boolean quitCountDownOn = kODFalse;
- ODULong countDownStartTime;
-
- gQuitTime = TickCount() + kOLQuitDelay;
-
- while( ! ShouldIQuit() )
- {
- TRY
- WaitNextEvent(everyEvent, &anEvent, GetSleepTime(), (RgnHandle) nil);
-
- switch (anEvent.what)
- {
- case kHighLevelEvent:
- error = AEProcessAppleEvent(&anEvent);
- #if ODDebug
- if (error && (error != errAEEventNotHandled))
- ReportErrorWithNum("\pError processing Apple event.", error);
- #endif
- // AFTER HANDLING HIGH LEVEL EVENT, QUIT IF IT'S APPROPRIATE
- if (!gShouldRun)
- gShouldQuit = kODTrue;
- break;
-
- default:
- break;
- }
- if (!gRunUntilQuitEvent)
- {
- if (!AreODDocumentsRunning())
- {
- if (!quitCountDownOn)
- {
- quitCountDownOn = kODTrue;
- countDownStartTime = TickCount();
- }
- else
- {
- if (TickCount() - countDownStartTime > kNLQuitDelay)
- gShouldQuit = kODTrue;
- }
- }
- else
- quitCountDownOn = kODFalse;
- }
- CATCH_ALL
- WARN("Throw in main event loop!", ErrorCode());
- ENDTRY
- }
- // CLEAN UP. WE DO THIS FOR *EVERY* QUIT. BUT IT SHOULDN'T TAKE
- // NOTICABLE TIME.
- // if (gIsSystem753OrLater)
- // DeleteOldLauncher();
- }
-
- //------------------------------------------------------------------------------
- // ShouldIQuit
- //------------------------------------------------------------------------------
-
- static ODBoolean ShouldIQuit()
- {
- return gShouldQuit && (gPendingNotifications == 0);
- }
-
- //------------------------------------------------------------------------------
- // HandleQuit
- //------------------------------------------------------------------------------
-
- static pascal OSErr HandleQuit( const AppleEvent*, AppleEvent*, long )
- {
- gShouldQuit = true;
-
- return noErr;
- }
-
- //------------------------------------------------------------------------------
- // GetSleepTime
- //------------------------------------------------------------------------------
-
- static long GetSleepTime()
- {
- return kSleepTime; // arbitrary for now
- }
-
- //------------------------------------------------------------------------------
- // NotifyLaunchFailed
- //
- // See also OpenDocX.cpp-NotifyLaunchFailed
- //
- // We do ParamText-style substitutions here using the ^0, ^1, etc. sequences.
- //
- // Note that the substitutions done here are 2 levels deep. Substitutions
- // are done into the string found at kODSysProcStringsID, 1. The second
- // substitution "^1" is done with a string found at kLaunchFailedErrStrings
- // which may have additional (^2 and/or ^3) substitution sequences.
- //------------------------------------------------------------------------------
-
- void NotifyLaunchFailed(OSErr errorCode, Str255 appName, Str255 libName)
- {
- Str255 templateString;
- Handle templateStringH = NULL;
- Str255 tempString;
- Handle tempStringH;
- short index;
- short ignoreValue;
-
- TRY
- templateString[0] = 0;
- tempString[0] = 0;
- GetIndString(templateString, kODSysProcStringsID,
- kODSPStrIndexComplexErrMssg);
- THROW_IF_ERROR(PtrToHand(templateString + 1, &templateStringH,
- templateString[0]));
-
- THROW_IF_ERROR(PtrToHand(appName + 1, &tempStringH, appName[0]));
- ignoreValue = ReplaceText(templateStringH, tempStringH, "\p^0");
- DisposeHandle(tempStringH);
-
- if( errorCode <= -2800 && errorCode >= -2824 )
- index = 2 - 2800 - errorCode; // Maps -2800..-2824 -> 2..26
- else
- index = 1;
- GetIndString(tempString, kLaunchFailedErrStrings, index);
- THROW_IF_ERROR(PtrToHand(tempString + 1, &tempStringH,
- tempString[0]));
- ignoreValue = ReplaceText(templateStringH, tempStringH, "\p^1");
- DisposeHandle(tempStringH);
-
- THROW_IF_ERROR(PtrToHand(libName + 1, &tempStringH, libName[0]));
- ignoreValue = ReplaceText(templateStringH, tempStringH, "\p^2");
- DisposeHandle(tempStringH);
-
- NumToString(errorCode, tempString);
- THROW_IF_ERROR(PtrToHand(tempString + 1, &tempStringH,
- tempString[0]));
- ignoreValue = ReplaceText(templateStringH, tempStringH, "\p^3");
- DisposeHandle(tempStringH);
-
- Size handleSize = GetHandleSize(templateStringH);
- THROW_IF_ERROR(MemError());
- if (handleSize > UCHAR_MAX)
- handleSize = UCHAR_MAX;
- templateString[0] = handleSize;
- ODBlockMove(*templateStringH, templateString + 1, handleSize);
-
- ReportError(templateString);
- CATCH_ALL
- ENDTRY
-
- if (templateStringH)
- DisposeHandle(templateStringH);
- }
-
- //------------------------------------------------------------------------------
- // ReportDocumentError
- //
- // See NotifyLaunchFailed for implementation notes. Only a simple one stage
- // substitution is done here.
- //------------------------------------------------------------------------------
-
- void ReportDocumentError(StringPtr docName, OSErr err)
- {
- Str255 templateString;
- Handle templateStringH = NULL;
- Str255 tempString;
- Handle tempStringH;
- short ignoreValue;
-
- TRY
- templateString[0] = 0;
- tempString[0] = 0;
-
- short stringIndex = docName[0] ? kODSPStrIndexTwoPartErrMssg
- : kODSPStrIndexOnePartErrMssg;
-
- GetIndString(templateString, kODSysProcStringsID,
- stringIndex);
- THROW_IF_ERROR(PtrToHand(templateString + 1, &templateStringH,
- templateString[0]));
-
- if (docName[0])
- {
- THROW_IF_ERROR(PtrToHand(docName + 1, &tempStringH, docName[0]));
- ignoreValue = ReplaceText(templateStringH, tempStringH, "\p^0");
- DisposeHandle(tempStringH);
- }
-
- NumToString(err, tempString);
- THROW_IF_ERROR(PtrToHand(tempString + 1, &tempStringH, tempString[0]));
- ignoreValue = ReplaceText(templateStringH, tempStringH, "\p^1");
- DisposeHandle(tempStringH);
-
- Size handleSize = GetHandleSize(templateStringH);
- THROW_IF_ERROR(MemError());
- if (handleSize > UCHAR_MAX)
- handleSize = UCHAR_MAX;
- templateString[0] = handleSize;
- ODBlockMove(*templateStringH, templateString + 1, handleSize);
- DisposeHandle(templateStringH);
- ReportError(templateString);
- CATCH_ALL
- ENDTRY
-
- if (templateStringH)
- DisposeHandle(templateStringH);
- }
-
- //------------------------------------------------------------------------------
- // ReportErrorGeneric
- //------------------------------------------------------------------------------
-
- void ReportErrorGeneric(StringPtr errorString)
- {
- ReportError(errorString);
- }
-
- //------------------------------------------------------------------------------
- // ReportErrorWithNum
- //
- // Append error number to message
- //------------------------------------------------------------------------------
-
- static void ReportErrorWithNum(StringPtr errorString, OSErr error)
- {
- Str255 errNumString;
- Str255 destString;
-
- NumToString(error, errNumString);
- CopyPascalString(destString, (StringPtr)errorString);
- ConcatPascalStrings(destString, "\p: ");
- ConcatPascalStrings(destString, errNumString);
- InstallNotification(destString);
- }
-
- //------------------------------------------------------------------------------
- // ReportError
- //------------------------------------------------------------------------------
-
- static void ReportError(StringPtr errorString)
- {
- InstallNotification(errorString);
- }
-
- //------------------------------------------------------------------------------
- // NotifyRecord
- //------------------------------------------------------------------------------
-
- class NotifyRecord
- {
- public:
- NotifyRecord(StringPtr string);
-
- private:
- NMRec notifyRec;
- Str255 message;
- static NMUPP notifyResponse;
-
- static pascal void RemoveNotificationRecord(NMRec* notifyRec);
- };
-
- NMUPP NotifyRecord::notifyResponse
- = NewNMProc(NotifyRecord::RemoveNotificationRecord);
-
- //------------------------------------------------------------------------------
- // NotifyRecord::NotifyRecord
- //------------------------------------------------------------------------------
-
- NotifyRecord::NotifyRecord(StringPtr string)
- {
- memset(&(this->notifyRec), 0, sizeof(this->notifyRec));
- this->notifyRec.qType = nmType;
- this->notifyRec.nmMark = true;
- this->notifyRec.nmIcon = NULL;
- this->notifyRec.nmSound = NULL;
- CopyPascalString(message, string);
- this->notifyRec.nmStr = message;
- this->notifyRec.nmResp = this->notifyResponse;
- this->notifyRec.nmRefCon = (long)this;
-
- WASSERT(!NMInstall(&this->notifyRec));
- ++gPendingNotifications;
- }
-
- //------------------------------------------------------------------------------
- // NotifyRecord::RemoveNotificationRecord (Notification Mgr. reponse routine)
- //------------------------------------------------------------------------------
-
- pascal void NotifyRecord::RemoveNotificationRecord(NMRec* notifyRec)
- {
- // Save this off because notifyRec isn't valid after calling NMRemove.
- NotifyRecord* myRec = (NotifyRecord*)notifyRec->nmRefCon;
-
- WASSERT(!NMRemove(notifyRec));
- delete myRec; // do this after since notifyRec is a pointer into myRec.
- --gPendingNotifications;
- }
-
- //------------------------------------------------------------------------------
- // InstallNotification
- //------------------------------------------------------------------------------
-
- pascal void InstallNotification(StringPtr errorString)
- {
- NotifyRecord* nRec = new NotifyRecord(errorString);
- }
-
- //------------------------------------------------------------------------------
- // DocumentLaunched
- //
- // We probably want to record that we are waiting for a launch failure apple
- // event so that we don't quit before we receive it.
- //------------------------------------------------------------------------------
-
- void DocumentLaunched()
- {
- // Give time for error to come back
- gQuitTime = TickCount() + kWaitForErrorDelay;
- }
-
- //------------------------------------------------------------------------------
- // GetOurCreator
- //------------------------------------------------------------------------------
-
- static OSType GetOurCreator()
- {
- TempPlatformFile file = new PlatformFile;
-
- file->Specify(&gFileSpec);
-
- return file->GetPlatformCreator();
- }
-
- //------------------------------------------------------------------------------
- // ChangeOurCreator
- //------------------------------------------------------------------------------
-
- static void ChangeOurCreator(OSType type)
- {
- TRY
- TempPlatformFile file = new PlatformFile;
-
- file->Specify(&gFileSpec);
-
- file->SetPlatformCreator(type);
- CATCH_ALL
- ENDTRY
- }
-
- #if !GENERATINGCFM
- //------------------------------------------------------------------------------
- // CFMIsPresent
- //------------------------------------------------------------------------------
-
- ODBoolean CFMIsPresent()
- {
- long gestaltResponse;
- ODBoolean answer = kODTrue;
-
- OSErr error = Gestalt(gestaltCFMAttr, &gestaltResponse);
- if (error != noErr || !(gestaltResponse & (1<<gestaltCFMPresent)))
- {
- ReportErrorWithNum("\pCFM must be installed to use OpenDoc."
- " Try reinstalling OpenDoc.", error);
- answer = kODFalse;
- }
-
- return answer;
- }
- #endif
- //------------------------------------------------------------------------------
- // ReenableLauncher
- //------------------------------------------------------------------------------
-
- OSErr ReenableLauncher()
- {
- FSSpec fileSpec;
- OSErr error;
-
- // TRY TO FIND LAUNCHER WHERE THE INSTALLER PUTS IT
- CopyPascalString(fileSpec.name, *GetString(kSHLLauncherNameResID));
- error = GetOpenDocLibsFolderInfo(&fileSpec.parID, &fileSpec.vRefNum);
- if (!error)
- error = EnableAppIfNotAlready(&fileSpec);
-
- if (error)
- {
- // MAYBE IT HAS BEEN RENAMED
- error = FindODLibFileWithSignature(fileSpec.name,
- fileSpec.vRefNum,
- fileSpec.parID,
- kODDisabledProcessSignature);
- if (!error)
- error = EnableAppIfNotAlready(&fileSpec);
-
- // if (error)
- // DIDN'T FIND IT IN THE NORMAL PLACE, LET'S LOOK ELSEWHERE AND TRY
- // TO FIND ONE LAUNCHER THAT WE CAN ENABLE
- // error = DoCatSearchesAndEnable(kODDisabledProcessSignature);
- }
-
- return error;
- }
-
- //------------------------------------------------------------------------------
- // DoCatSearchesAndEnable
- //
- // Looks for process by creator type and calls EnableAppIfNotAlready if found
- //------------------------------------------------------------------------------
-
- OSErr DoCatSearchesAndEnable(OSType creator)
- {
- ODBoolean succeeded = kODFalse;
-
- ODVolatile(succeeded);
-
- TRY
- StVolumeLoop volumeLoop;
- short theVolume;
- ODBoolean foundAMatchHere = kODFalse;
- OSErr error;
-
- CSParam catSearchPB;
- CInfoPBRec catSearchInfoPB1;
- CInfoPBRec catSearchInfoPB2;
- HParamBlockRec volumeInfoPB;
- GetVolParmsInfoBuffer volParmsInfoBufferPB;
- Ptr searchBuffer = NULL;
- long searchBufferSize = 15*1024; // 15K
- FSSpec matchedFileSpec;
- Handle hVolumeList = NULL;
-
- searchBuffer = (Ptr)ODNewPtr(searchBufferSize);
-
- while (!succeeded && volumeLoop.NextVolume(theVolume))
- {
- // CHECK TO SEE IF VOLUME SUPPORTS CATSEARCH
- memset(&volumeInfoPB, 0, sizeof(volumeInfoPB));
- memset(&volParmsInfoBufferPB, 0, sizeof(volParmsInfoBufferPB));
- volumeInfoPB.ioParam.ioVRefNum = theVolume;
- volumeInfoPB.ioParam.ioBuffer = (Ptr)&volParmsInfoBufferPB;
- volumeInfoPB.ioParam.ioReqCount = sizeof(volParmsInfoBufferPB);
-
- error = PBHGetVolParmsSync(&volumeInfoPB);
- if ((error) || (volumeInfoPB.ioParam.ioReqCount !=
- volumeInfoPB.ioParam.ioActCount))
- {
- WARN("FindLauncher: Error from PBHGetVolParms.");
- continue;
- }
- if (!(volParmsInfoBufferPB.vMAttrib & 1<<bHasCatSearch))
- {
- WARN("FindLauncher: Volume doesn't support CatSearch.");
- continue;
- }
-
- // DO THE SEARCH
- memset(&catSearchInfoPB1, 0, sizeof(catSearchInfoPB1));
- memset(&catSearchInfoPB2, 0, sizeof(catSearchInfoPB2));
-
- catSearchInfoPB1.hFileInfo.ioNamePtr = 0; // not searching for name
- catSearchInfoPB1.hFileInfo.ioFlFndrInfo.fdCreator
- = creator;
- // catSearchInfoPB1.hFileInfo.ioFlFndrInfo.fdType = 'MPSP';
-
- catSearchInfoPB2.hFileInfo.ioFlFndrInfo.fdCreator = 0xFFFFFFFF;
- // catSearchInfoPB2.hFileInfo.ioFlFndrInfo.fdType = 0xFFFFFFFF;
-
- memset(&catSearchPB, 0, sizeof(catSearchPB));
- catSearchPB.ioMatchPtr = &matchedFileSpec;
- catSearchPB.ioVRefNum = theVolume;
- catSearchPB.ioSearchInfo1 = &catSearchInfoPB1;
- catSearchPB.ioSearchInfo2 = &catSearchInfoPB2;
- catSearchPB.ioReqMatchCount = 1;
- catSearchPB.ioSearchTime = 1;
- catSearchPB.ioOptBuffer = searchBuffer;
- catSearchPB.ioOptBufSize = searchBufferSize;
-
- catSearchPB.ioSearchBits = fsSBFlFndrInfo;
-
- do
- {
- error = PBCatSearchSync(&catSearchPB);
- if ((error != 0) && (error != eofErr))
- WARN("Error from PBCatSearch");
- if ((! error) && (catSearchPB.ioActMatchCount != 0))
- {
- error = EnableAppIfNotAlready(&matchedFileSpec);
- if (!error)
- succeeded = kODTrue;
- }
- }
- while (!error && !succeeded);
- }
- ODDisposePtr(searchBuffer);
- CATCH_ALL
- WARN("DoCatSearchesAndEnable: Throw detected, error: %d", ErrorCode());
- succeeded = kODFalse;
- ENDTRY
-
- return succeeded ? noErr : fnfErr;
- }
-
- //------------------------------------------------------------------------------
- // EnableApp
- //------------------------------------------------------------------------------
-
- OSErr EnableApp(FSSpec* fileSpec)
- {
- OSErr result = noErr;
-
- ODVolatile(result);
-
- TRY
- TempPlatformFile file = new PlatformFile;
-
- file->Specify(fileSpec);
-
- file->SetPlatformCreator(kODShellSignature);
- ChangeDesktopDatabase(fileSpec, kODAddAPPL);
- CATCH_ALL
- result = ErrorCode();
- ENDTRY
-
- return result;
- }
-
- //------------------------------------------------------------------------------
- // EnableAppIfNotAlready
- //
- // Don't want to hit the desktop database if we don't have to.
- //------------------------------------------------------------------------------
-
- OSErr EnableAppIfNotAlready(FSSpec* fileSpec)
- {
- OSErr result = noErr;
- OSType type;
-
- ODVolatile(result);
-
- TRY
- TempPlatformFile file = new PlatformFile;
-
- file->Specify(fileSpec);
-
- type = file->GetPlatformCreator();
- if (type != kODShellSignature)
- {
- file->SetPlatformCreator(kODShellSignature);
- ChangeDesktopDatabase(fileSpec, kODAddAPPL);
- }
- CATCH_ALL
- result = ErrorCode();
- ENDTRY
-
- return result;
- }
-
- //------------------------------------------------------------------------------
- // DisableApp
- //------------------------------------------------------------------------------
-
- void DisableApp(FSSpec* fileSpec, OSType newSignature)
- {
- TRY
- TempPlatformFile file = new PlatformFile;
-
- file->Specify(fileSpec);
-
- file->SetPlatformCreator(newSignature);
- ChangeDesktopDatabase(fileSpec, kODRemoveAPPL);
- CATCH_ALL
- ENDTRY
- }
-
- //------------------------------------------------------------------------------
- // DeleteOldLauncher
- //
- // The launcher will rename itself to kSHLOldLauncherNameResID when the user
- // upgrades his system to 7.5.3 or greater from an earlier system. Then we
- // can feel free to delete this useless file here.
- //------------------------------------------------------------------------------
-
- void DeleteOldLauncher()
- {
- FSSpec fileSpec;
- OSErr error;
-
- CopyPascalString(fileSpec.name, *GetString(kSHLOldLauncherNameResID));
- error = GetOpenDocLibsFolderInfo(&fileSpec.parID, &fileSpec.vRefNum);
- if (!error)
- error = FSpDelete(&fileSpec);
- }
-
- //------------------------------------------------------------------------------
- // HandleControlMessage
- //
- // Handle messages from the OpenDoc Setup control panel.
- //------------------------------------------------------------------------------
-
- static pascal OSErr HandleControlMessage(const AppleEvent* message,
- AppleEvent* reply,
- long refCon)
- {
- long controlMessage;
- DescType actualType;
- Size actualSize;
- OSErr error;
-
- error = AEGetParamPtr(message, kControlMessageKeyword, typeInteger,
- &actualType, (Ptr)&controlMessage,
- sizeof(controlMessage), &actualSize);
- if (!error
- && actualType != typeInteger
- && actualSize != sizeof(controlMessage))
- error = errAECorruptData;
-
- if (!error)
- {
- if (controlMessage == kRunUntilQuitEvent)
- gRunUntilQuitEvent = true;
- else if (controlMessage == kShutdownAtLastDocQuit)
- gRunUntilQuitEvent = false;
- }
-
- return error;
- }
-
- //------------------------------------------------------------------------------
- // CheckPrefs
- //
- // Check the preferences for information about how long to stay running.
- //------------------------------------------------------------------------------
-
- void CheckPrefs()
- {
- ODSetUpPrefs prefs(-1, 0);
-
- gRunUntilQuitEvent = prefs.GetRunTilSysShutdown();
- }
-
- //------------------------------------------------------------------------------
- // CheckForCorrectName
- //
- // OpenDoc™ -> some disabled name
- // Ourselves -> "OpenDoc™"
- //------------------------------------------------------------------------------
-
- void CheckForCorrectName()
- {
- FSSpec launcherFileSpec;
- OSErr error;
- Str255 oldLauncherName;
- Str255 newNameForSystemProcess;
-
- // GET THE "OpenDoc™" NAME AND COMPARE IT TO OURS
- CopyPascalString(newNameForSystemProcess,
- *GetString(kSHLLauncherNameResID));
- if (!EqualPascalStrings(gFileSpec.name, *GetString(kSHLLauncherNameResID)))
- {
- // TRY TO FIND LAUNCHER WHERE THE INSTALLER PUTS IT
- CopyPascalString(launcherFileSpec.name,
- *GetString(kSHLLauncherNameResID));
- error = GetOpenDocLibsFolderInfo(&launcherFileSpec.parID,
- &launcherFileSpec.vRefNum);
- if (!error)
- {
- CopyPascalString(oldLauncherName,
- *GetString(kSHLOldLauncherNameResID));
- ChangeDesktopDatabase(&launcherFileSpec, kODRemoveAPPL);
- error = FSpRename(&launcherFileSpec, oldLauncherName);
- if (!error || error == fnfErr)
- {
- ChangeDesktopDatabase(&gFileSpec, kODRemoveAPPL);
- error = FSpRename(&gFileSpec, newNameForSystemProcess);
- if (!error)
- CopyPascalString(gFileSpec.name, newNameForSystemProcess);
- ChangeDesktopDatabase(&gFileSpec, kODAddAPPL);
- }
- }
- }
- }
-
- //------------------------------------------------------------------------------
- // SystemIsTooOld
- //------------------------------------------------------------------------------
-
- ODBoolean SystemIsTooOld()
- {
- Str255 errorString;
- OSErr error;
- short systemVersion;
- Str255 sysVersString;
- Str255 tempString;
- Str255 ourVersString;
- short bugFixNumber;
- long response;
- Handle errorStringH = NULL;
- Handle tempStringH;
- short ignoreValue;
-
- error = Gestalt(gestaltSystemVersion, &response);
- WASSERTM(error == noErr, "Gestalt failed! What?");
- systemVersion = LoWord(response);
-
- if (systemVersion < kOD1pt2EarliestCompatibleSysVersNum)
- {
- // Need to convert a system version number to a string
- // Convert byte 2
- NumToString((systemVersion & 0x0F00) >> 8, sysVersString);
- ConcatPascalStrings(sysVersString, "\p.");
- // convert byte 1
- NumToString((systemVersion & 0x00F0) >> 4, tempString);
- ConcatPascalStrings(sysVersString, tempString);
- // convert byte 0
- bugFixNumber = systemVersion & 0x000F;
- if (bugFixNumber != 0)
- {
- NumToString(bugFixNumber, tempString);
- ConcatPascalStrings(sysVersString, "\p.");
- ConcatPascalStrings(sysVersString, tempString);
- }
- // Extract version number from our vers resource
- VersRsrc** vers = (VersRsrc**) Get1Resource('vers', 2);
- if( vers )
- {
- ODBlockMove((**vers).versionStr, ourVersString,
- ((**vers).versionStr)[0] + 1);
- ReleaseResource((Handle)vers);
- }
- else
- // Hard-coded string OK because this failure indicates a build
- // error. Will never happen in a shipping version.
- CopyPascalString(ourVersString, "\p<Error. No 'vers' 2 resource in \"OpenDoc™\"");
-
- // ParamText("\p????", sysVersString, NULL, NULL);
-
- // Get the error string
- GetIndString(errorString, kODSysProcStringsID,
- kODSPStrIndexWrongVersSys);
- // Do substitutions into the error string
- TRY
- // Convert error string to a handle
- THROW_IF_ERROR(PtrToHand(errorString + 1, &errorStringH,
- errorString[0]));
- // convert first sub. string to a handle and replace
- THROW_IF_ERROR(PtrToHand(ourVersString + 1, &tempStringH,
- ourVersString[0]));
- ignoreValue = ReplaceText(errorStringH, tempStringH, "\p^0");
- DisposeHandle(tempStringH);
- // convert second sub. string to a handle and replace
- THROW_IF_ERROR(PtrToHand(sysVersString + 1, &tempStringH,
- sysVersString[0]));
- ignoreValue = ReplaceText(errorStringH, tempStringH, "\p^1");
- DisposeHandle(tempStringH);
- // convert handle back to a string
- Size handleSize = GetHandleSize(errorStringH);
- THROW_IF_ERROR(MemError());
- if (handleSize > UCHAR_MAX)
- handleSize = UCHAR_MAX;
- errorString[0] = handleSize;
- ODBlockMove(*errorStringH, errorString + 1, handleSize);
- CATCH_ALL
- // If the substitution doesn't finish, we can at least show some
- // of the error message, so don't reraise.
- ENDTRY
-
- // cleanup
- if (errorStringH)
- DisposeHandle(errorStringH);
-
- ReportErrorGeneric(errorString);
- return kODTrue;
- }
- return kODFalse;
- }
-
- //------------------------------------------------------------------------------
- // HandleCloseReopenEvent
- //
- // This event is sent by a document that wants to be closed and reopened
- // (probably after the user changed the memory setting).
- //------------------------------------------------------------------------------
-
- #define CATCHERROR(x) error = x; if (error) goto cleanup;
-
- static pascal OSErr HandleCloseReopenEvent(const AppleEvent* message,
- AppleEvent* reply,
- long refCon)
- {
- FSSpec* fileSpec = (FSSpec*)NewPtrClear(sizeof(FSSpec));
- DescType actualType = 0;
- Size actualSize = 0;
- OSErr error = noErr;
- AEDesc address = NULL_DESCRIPTOR_DEFINITION;
- LaunchParamBlockRec launchPB;
- AEDescList docList = NULL_DESCRIPTOR_DEFINITION;
- AEDesc aliasDesc = NULL_DESCRIPTOR_DEFINITION;
- AppleEvent openDocumentsEvent = NULL_DESCRIPTOR_DEFINITION;
- AEDesc launchDesc = NULL_DESCRIPTOR_DEFINITION;
- unsigned long currentTickCount = 0;
- unsigned long savedTickCount = 0;
- ProcessSerialNumber iteratorPSN; // used to iterate only.
- ODBoolean docIsRunning = kODFalse;
- ODBoolean docIsStillRunning = kODTrue;
- ODBoolean sameProcResult = kODFalse;
- ProcessSerialNumber* psn = kODNULL;
-
- // Get the psn of the caller
- error = AEGetParamDesc(message, 'duhh', typeProcessSerialNumber, &address);
-
- if( error != noErr )
- goto cleanup;
-
- // Get the FSSpec of the caller
- error = AEGetParamPtr(message, keyDirectObject, typeFSS, &actualType,
- fileSpec, sizeof(FSSpec), &actualSize);
-
- if( error != noErr )
- goto cleanup;
-
- if (actualType != typeFSS
- && actualSize != sizeof(FSSpec))
- CATCHERROR(errAECorruptData);
-
- AppleEvent newEvent = NULL_DESCRIPTOR_DEFINITION;
- AppleEvent newReply = NULL_DESCRIPTOR_DEFINITION;
-
- // Create and send close/quit event
- CATCHERROR(AECreateAppleEvent(kCoreEventClass, kAEQuitApplication,
- &address,
- kAutoGenerateReturnID, kAnyTransactionID,
- &newEvent));
- CATCHERROR(AESend(&newEvent, &newReply,
- kAENoReply + kAECanInteract + kAECanSwitchLayer
- + kAEDontRecord,
- kAEHighPriority,
- kAEDefaultTimeout, NULL, NULL));
-
- // Idle until the process goes away
- iteratorPSN.highLongOfPSN = 0;
- iteratorPSN.lowLongOfPSN = kNoProcess;
-
- HLock( address.dataHandle );
- psn = new ProcessSerialNumber;
- BlockMoveData( (Ptr)(*address.dataHandle), psn, sizeof(ProcessSerialNumber) );
- HUnlock(address.dataHandle);
-
- // Start timing count
- savedTickCount = TickCount();
-
- // Make sure document is still open iterating, waiting until it closes.
- while (error != procNotFound)
- {
- error = GetNextProcess(&iteratorPSN);
- if (!error)
- {
- SameProcess(psn, &iteratorPSN,&sameProcResult);
- if( sameProcResult )
- docIsStillRunning = kODTrue;
- }
- // Only wait a certain amount of time. After that, discontinue processing event.
- currentTickCount = TickCount();
- if( currentTickCount > ( savedTickCount + kWaitNumTicks ) )
- break;
- }
-
- // Now wait for it to actually go away before sending open event below.
- if( docIsStillRunning )
- {
- EventRecord anEvent;
-
- iteratorPSN.highLongOfPSN = 0;
- iteratorPSN.lowLongOfPSN = kNoProcess;
- error = noErr;
-
- while (docIsStillRunning )
- {
- docIsStillRunning = kODFalse;
- error = noErr;
- // Go through the entire process list looking for the document.
- while (error != procNotFound)
- {
- error = GetNextProcess(&iteratorPSN);
- if (!error)
- {
- SameProcess(psn, &iteratorPSN,&sameProcResult);
- if( sameProcResult )
- docIsStillRunning = kODTrue;
- }
- }
- // The other process some time to handle an event.
- WaitNextEvent(everyEvent, &anEvent, 1, (RgnHandle) nil);
-
- // Only wait a certain amount of time. After that, discontinue processing event.
- currentTickCount = TickCount();
- if( currentTickCount > (savedTickCount + kWaitForDocClosedTicks ) )
- {
- WARN("Couldn't reopen document because it didn't quit first.");
- break;
- }
- }
-
- if( docIsStillRunning == kODFalse )
- {
- // Launch the doc
-
- launchPB.launchBlockID = extendedBlock;
- launchPB.launchEPBLength = extendedBlockLen;
- launchPB.launchControlFlags = launchContinue
- | launchUseMinimum
- | launchInhibitDaemon;
- launchPB.launchAppSpec = fileSpec;
-
- // Must pass the doc itself as the parameter to the open document event!
- CATCHERROR( NewAlias(NULL, fileSpec, (AliasHandle*)&aliasDesc.dataHandle) );
- aliasDesc.descriptorType = typeAlias;
- CATCHERROR(AECreateList(NULL, 0, false, &docList));
- CATCHERROR(AEPutDesc(&docList, 0, &aliasDesc));
- // Just need a null desc for 3rd param, so I reuse launchDesc.
- CATCHERROR(AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &launchDesc,
- kAutoGenerateReturnID, kAnyTransactionID,
- &openDocumentsEvent));
- CATCHERROR(AEPutParamDesc(&openDocumentsEvent, keyDirectObject, &docList));
- CATCHERROR(AECoerceDesc(&openDocumentsEvent, typeAppParameters,
- &launchDesc));
- /*
- This may look a little weird, since we're actually moving the event out of
- the AppParameters descriptor. But it's necessary, the coercison to
- typeAppParameters takes the 'aevt' and puts it all in one handle, instead
- of leaving it as a AEDesc. So, only one handle is being added to
- the launch parameter block instead of an AEDesc.
- */
- HLock(launchDesc.dataHandle);
- launchPB.launchAppParameters = (AppParametersPtr)*(launchDesc.dataHandle);
- error = LaunchApplication(&launchPB);
- }
- }
- cleanup:
- AEDisposeDesc(&newEvent);
- AEDisposeDesc(&newReply);
- AEDisposeDesc(&address);
- AEDisposeDesc(&docList);
- AEDisposeDesc(&aliasDesc);
- AEDisposeDesc(&openDocumentsEvent);
- AEDisposeDesc(&launchDesc);
-
- if (error)
- {
- Str255 errorString;
- if( error == fnfErr )
- // Couldn't reopen document because the file is missing. This usually
- // happens because the user created a document from stationery, then
- // when closing the document, didn't choose to save, so OpenDoc trashed it.
- GetIndString(errorString, kODSysProcStringsID,
- kODSPStrIndexMissingDocument);
- else
- GetIndString(errorString, kODSysProcStringsID,
- kODSPStrIndexCouldntRelaunchDoc);
- ReportErrorWithNum(errorString, error);
- }
-
- // Don't return an error here since we have already reported it to the user.
- return noErr;
- }
-
-